package multithreading;

public class Demo5_SailTicketsByRunnable_share {

    public static void main(String[] args) {

        //创建一个线程类的对象，多个线程共享这个对象的资源
        Ticket_lock ticket = new Ticket_lock();

        //使用同一个对象，创建三个线程
        Thread th_hrb = new Thread(ticket);
        th_hrb.setName("哈尔滨");
        Thread th_bj = new Thread(ticket);
        th_bj.setName("北京");
        Thread th_sh = new Thread(ticket);
        th_sh.setName("上海");

        th_hrb.start();
        th_bj.start();
        th_sh.start();

    }

}

/**
 * 自定义一个共享资源的卖票的线程类
 */
class Ticket_block implements Runnable{

    int ticketsCount = 100;

    @Override
    public void run() {

        /**
         * 共享资源会产生资源恶性竞争的问题，对使用者的直观感受就是数据是乱的是错误的
         *   解决这个问题的方式：加锁
         *     同步块/同步锁(方法):同一个时刻只允许一个线程执行块(方法)中的代码
         *     哪个线程拿到了这个对象(this)这个线程执行代码。其他线程只能等待
         *
         *     这个对象指的monitor(监视器)
         */
        try {
            while(true){
                //只能在while内锁定，锁定当前这张票
                synchronized (this){

                    //当前线程抢占到此对象的时候，其他线程也在抢，只不过是在等待当前线程释放锁，所以一定要先做判断
                    if(ticketsCount<=0){
                        break;
                    }

                    //执行一次，卖一张票
                    ticketsCount--;

                    //因为是共享资源，所以此类只能有一个对象，所以此处通过线程名进行控制
                    System.out.println(Thread.currentThread().getName()+"卖了一张车票，剩余："+ticketsCount+"张火车票");

                    Thread.sleep(500);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}


class Ticket_lock implements Runnable{

    int ticketsCount = 100;

    @Override
    public void run() {

        try {
            while(true){
                //当前线程抢占到此对象的时候，其他线程也在抢，只不过是在等待当前线程释放锁，所以一定要先做判断
                if(ticketsCount<=0){
                    break;
                }

                //把卖票的逻辑封装成一个同步方法，其他逻辑无需写在同步块中
                sailTicket();

                Thread.sleep(500);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public synchronized void sailTicket(){
        //执行一次，卖一张票
        ticketsCount--;
        //因为是共享资源，所以此类只能有一个对象，所以此处通过线程名进行控制
        System.out.println(Thread.currentThread().getName()+"卖了一张车票，剩余："+ticketsCount+"张火车票");
    }
}
